雖然對競程來說觀察性質非常重要,有時不管怎麼觀察也想不出解法,這時就需要「枚舉演算法」了。
枚舉演算法就是把你想得到的算法都列舉出來,就算題目看起來很像數學,也要想是否有圖論解法。
但是,這樣似乎很沒有效率,因為演算法種類實在太多了,要怎麼優化呢?
如果題目給你一個長度 n<=10^6 的數列,那麼算法複雜度肯定不是 O(n^2),或是更大的複雜度。
因此我們可以依照 n 的上限,枚舉常見時間複雜度,例如 2^n, n^2, nlog(n), n 等。
不過,只看時間複雜度找算法還是有其限制。
有些複雜度不常見,像是 O(sqrt(n)),
或是複雜度常見但做法不易想到,例如 gcd,它的複雜度是 log(n)。
如果有 n,m 兩數,複雜度可能會是 O(mnlog(m+n)) 這樣的東西,幾乎不可能推得目標算法的類型。
另一種難題是解法分成好幾個步驟,第一步 O(nlog(n)),第二步 O(n^2),最終複雜度為 O(n^2)。
當然,你也可以先寫出必定超時的算法,再設法優化。
另一種方法是辨識特徵,
假設 n==17,答案有可能是 O(3^n) 的做法,
如果你做過很多經典題,可以發現枚舉子集也是 O(3^n),也許就這樣找到答案了。
使用此方法有兩個前提,一是你需要寫過非常多題,二是有意識地分析題目的異同,進而發現特徵。
後面的章節我也會舉出一些特徵。
老實說,如果你在 TOI 的賽場,看到題目一定會去想枚舉、DP等方法,因為比賽就是考這些。
但如果有一天,TOI 出題範圍偷偷改了呢?你花了好久的時間,勉強達成一個部份分,結果實際上要考的是 Buffer Overflow,你可能會想說:「好吧,是我想錯了,接下來 TOI 也可能考資安的題目,我應該去找找相關的資源。」
這很正確,也很正常。
你為了預測答案,而界定題目範圍,預測 TOI 某題之前,你早就預測了不會出資安題目。然後,你錯失了進一階的機會。
但現實社會處處都有這樣的預測和假設。
你努力唸書,就是為了考上好學校,但是你為什麼想考上好學校呢?
也許你希望父母開心,但每次考90幾分就足夠了?
你想幫助世人,除了進台清交成沒有更好的方法嗎?
更糟的是,有些人根本沒有目標,只因為處在這樣的社會環境,隨著同儕、老師走,最後什麼都沒剩下。
前西洋棋世界冠軍加里·卡斯帕洛夫曾說:「沒有計劃和長期目標,決策會陷於被動和純粹,受對手擺佈,被眼前吸引。」
我當初進入程式競賽,就是如此。聽聞上二階可保送頂大,而一頭栽進去,那是我人生中最黑暗的時光。
到目前為止,如果我寫的東西對你有幫助,那很好。
但請不要忘記你人生中的枚舉,你確定目標,界定答案範圍後,才會知道你該做什麼。
明天我應該會講貪心,貪心的概念很簡單,但證明真TM難。